package lex.explorer.directory_on_catalog_model;

import java.awt.BorderLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.filechooser.FileSystemView;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;

import org.lex.explorer.AbstractExplorer;
import org.lex.explorer.model.FileSystemModel;
import org.lex.swing.Swings;
import org.lex.utils.SystemProperties;


public class DirectoryExplorer extends AbstractExplorer
{
	private JScrollPane scrollPane;
	private JTree tree;
	private FileTreeRenderer treeRenderer = null;
	private File directory = null;

	public static void main( String[] args )
	{
		Swings.setUseBoldMetalFont( false );
		Swings.show( new DirectoryExplorer(), false );
	}

	public DirectoryExplorer()
	{
		this( SystemProperties.userHome() );
	}

	public DirectoryExplorer( String directory )
	{
		this( new File( directory ) );
	}

	public DirectoryExplorer( File directory )
	{
		super();
		this.directory = directory;
		initialize();
	}

	public DirectoryExplorer( FileSystemModel model )
	{
		this();
	}

	@Override
	public File getDirectory()
	{
		return this.directory;
	}

	@Override
	public void setDirectory( File directory, boolean fireEvent )
	{
		log.fine( directory.toString() );
		File old = this.directory;
		this.findFile( directory );
		if( true == fireEvent )
			this.fireDirectoryChange( old, directory );
	}

	private void initialize()
	{
		this.setLayout( new BorderLayout() );
		this.add( getScrollPane(), BorderLayout.CENTER );
		this.findFile( this.directory );
	}

	private JScrollPane getScrollPane()
	{
		if( scrollPane == null )
		{
			scrollPane = new JScrollPane();
			scrollPane.setViewportView( getTree() );
		}
		return scrollPane;
	}

	private JTree getTree()
	{
		if( tree == null )
		{
			tree = new JTree();
			tree.setToggleClickCount( 1 );
			tree.setRootVisible( false );
			tree.setCellRenderer( this.getTreeRenderer() );
			tree.setModel( new FileSystemTreeModel() );
			tree.getSelectionModel().setSelectionMode( TreeSelectionModel.SINGLE_TREE_SELECTION );
			// tree selection listener
			tree.addMouseListener( new MouseAdapter(){
				@Override
				public void mousePressed( MouseEvent e )
				{
					if( MouseEvent.BUTTON1 != e.getButton() )
						return;
					TreePath path = tree.getPathForLocation( e.getX(), e.getY() );
					if( null == path )
						return;
					File dir = ((FileNode) path.getLastPathComponent()).getFile();
					File old = directory;
					directory = dir;
					fireDirectoryChange( old, dir );
				}
			} );
		}
		return tree;
	}

	private FileTreeRenderer getTreeRenderer()
	{
		if( null == treeRenderer )
		{
			this.treeRenderer = new FileTreeRenderer();
		}
		return this.treeRenderer;
	}

	/**
	 * Ensures the file is visible
	 * 
	 * @param fileToLocate
	 * @param selectFile
	 */
	private void findFile( File file )
	{
		if( file == null || false == file.exists() || false == file.isDirectory() )
			return;
		try
		{
			file = file.getCanonicalFile();
		}
		catch( Exception e )
		{
			return;
		}
		// split the full path into individual files to
		// locate them in the tree model
		FileSystemView fsv = FileSystemView.getFileSystemView();
		List<File> filePath = new ArrayList<File>();
		while( null != file )
		{
			filePath.add( file );
			file = fsv.getParentDirectory( file );
		}
		Collections.reverse( filePath );
		// start from the root
		List<TreeNode> nodePath = new ArrayList<TreeNode>();
		TreeNode root = (TreeNode) getTree().getModel().getRoot();
		nodePath.add( root );
		// ...and go through the tree model to find the files. Stop as
		// soon as path is completely found or if one of the files in the path
		// is not found.
		boolean found = true;
		TreeNode current = null;
		while( filePath.size() > 0 && found )
		{
			found = false;
			for( int i = 0, c = root.getChildCount(); i < c; i++ )
			{
				current = root.getChildAt( i );
				File f = ((FileNode) current).getFile();
				if( filePath.get( 0 ).equals( f ) )
				{
					nodePath.add( current );
					filePath.remove( 0 );
					root = current;
					found = true;
					break;
				}
			}
		}
		// select the path we found, it may be the file we were looking
		// for or a subpath only
		TreePath path = new TreePath( nodePath.toArray() );
		tree.setSelectionPath( path );
		tree.expandPath( path );
		tree.scrollPathToVisible( path );
	}
}
